#pragma once

#include "Misc/EngineEditorMacros.h"
#include "Object/Object.h"
#include "Math/Vec2.h"
#include "Math/Color.h"
#include "Widgets/Widget.h"
#include "MaterialGraphModel.h"
#include "MaterialGraphViewModel.m.h"

class RMaterialGraphModel;
class RMaterialGraphNodeViewModel;
class RMaterialGraphPinViewModel;
class RMaterialGraphPinModel;
class RMaterialGraphLinkViewModel;
class RWidget;


RCLASS()
class RMaterialGraphViewModel : public RObject
{
    ROBJECT

public:
    virtual void BindModel(TSharedObjectPtr<RMaterialGraphModel> InModel);

    SVec2 GetGraphOffset() const;
    void SetGraphOffset(SVec2 InOffset);

    float GraphScale= 1.0f;

protected:
    //the offset of the graph
    //the graph origin is at center of the graph widget
    //when the graph offset is 0,0
    //graph space X axis is from left to right
    //graph space Y axis is from top to bottom
    SVec2 GraphOffset= SVec2(0, 0);

public:
    const float MaxScale= 3.0f;
    const float MinScale= 0.5f;
    float WheelSpeed= 0.1f;


    int64_t GetNodeNum() const;
    TSharedObjectPtr<RMaterialGraphNodeViewModel> GetNode(int64_t Index) const;
    void AddNode(TSharedObjectPtr<RMaterialGraphNodeViewModel> NodeViewModel);
    TDelegate<void,int64_t> OnNodeAdded;
    void RemoveNode(TSharedObjectPtr<RMaterialGraphNodeViewModel> NodeViewModel);
    TDelegate<void,int64_t> OnNodeRemoved;

    int64_t GetLinkNum() const;
    TSharedObjectPtr<RMaterialGraphLinkViewModel> GetLink(int64_t Index) const;
    TDelegate<void,int64_t> OnLinkAdded;
    TDelegate<void,int64_t> OnLinkRemoved;

    TSharedObjectPtr<RMaterialGraphPinViewModel> FindPinViewModelByModel(TSharedObjectPtr<RMaterialGraphPinModel> InModel);

    void OnPinDragStarted(TSharedObjectPtr<RMaterialGraphPinViewModel> InPin);
    void OnPinDragEnded(TSharedObjectPtr<RMaterialGraphPinViewModel> InPin);
    bool IsLinking() const;
    SVec2 GetLinkingStartPos(TSharedObjectPtr<RWidget> InGrapgWidget);
    SVec2 GetLinkingEndPos(TSharedObjectPtr<RWidget> InGrapgWidget);

    SColor GetLinkingStartColor() const;
    SColor GetLinkingEndColor() const;

    template<typename NodeType>
    void AddNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget)
    {
        SVec2 WidgetSize=InGrapgWidget->PresentSize;

        //node left top position in graph space
        auto MousePosInGraph= 
            (InGrapgWidget->GetMousePositionInWidget()
            -WidgetSize*0.5f)
            /GraphScale
            -GetGraphOffset()
            ;
        
        GraphModel->AddNode(NodeType::StaticClass(),MousePosInGraph);
    }
    
    void AddFloatNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddVectorNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddPropertyNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddOperationNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddVectorOperationNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddSplitVectorNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddTextureNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddCameraNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddDelayBRDFNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);
    void AddUnlitNodeAtMouse(TSharedObjectPtr<RWidget> InGrapgWidget);

    void AddOperation(TSharedObjectPtr<RMaterialEditOperation> Operation);
    void RedoOperation(TSharedObjectPtr<RMaterialEditOperation> Operation);

    void SelectNode(TSharedObjectPtr<RMaterialGraphNodeViewModel> NodeViewModel);
    void OnSelectedNodeChanged(TSharedObjectPtr<RMaterialGraphNodeModel> InNodeModel);
    bool IsNodeSelected(TSharedObjectPtr<RMaterialGraphNodeViewModel> NodeViewModel) const;
    void DeleteSelectedNode();

    void OnCurrentOutputNodeChanged(TSharedObjectPtr<RMaterialGraphNodeModel> InNodeModel);
    bool IsCurrentOutputNode(TSharedObjectPtr<RMaterialGraphNodeViewModel> NodeViewModel) const;
protected:
    TWeakObjectPtr<RMaterialGraphModel> GraphModel;

    TVector<TSharedObjectPtr<RMaterialGraphNodeViewModel>> NodeViewModels;

    TVector<TSharedObjectPtr<RMaterialGraphLinkViewModel>> LinkViewModels;

    TSharedObjectPtr<RMaterialGraphNodeViewModel> SelectedNodeViewModel;

    TSharedObjectPtr<RMaterialGraphNodeViewModel> CurrentOutputNodeViewModel;

//linking 
protected:
    void SetLinkingStartPin(TSharedObjectPtr<RMaterialGraphPinViewModel> Pin);
    void SetLinkingEndPin(TSharedObjectPtr<RMaterialGraphPinViewModel> Pin);
    void StopLinking();
    
    TSharedObjectPtr<RMaterialGraphPinViewModel> LinkingStartPin;
    TSharedObjectPtr<RMaterialGraphPinViewModel> LinkingEndPin;
    TSharedObjectPtr<RMaterialGraphPinViewModel> SnapedPin;
};